Skip to content

Commit 4e21c77

Browse files
committedMay 13, 2019
[ELF] Full support for -n (--nmagic) and -N (--omagic) via common page
The -n (--nmagic) disables page alignment, and acts as a -Bstatic The -N (--omagic) does what -n does but also marks the executable segment as writeable. As page alignment is disabled headers are not allocated unless explicit in the linker script. To disable page alignment in LLD we choose to set the page sizes to 1 so that any alignment based on the page size does nothing. To set the Target->PageSize to 1 we implement -z common-page-size, which has the side effect of allowing the user to set the value as well. Setting the page alignments to 1 does mean that any use of CONSTANT(MAXPAGESIZE) or CONSTANT(COMMONPAGESIZE) in a linker script will return 1, unlike in ld.bfd. However given that -n and -N disable paging these probably shouldn't be used in a linker script where -n or -N is in use. Differential Revision: https://reviews.llvm.org/D61688 llvm-svn: 360593
1 parent d3cedee commit 4e21c77

14 files changed

+515
-22
lines changed
 

‎lld/ELF/Arch/SPARCV9.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ SPARCV9::SPARCV9() {
4141
PltEntrySize = 32;
4242
PltHeaderSize = 4 * PltEntrySize;
4343

44-
PageSize = 8192;
44+
DefaultCommonPageSize = 8192;
4545
DefaultMaxPageSize = 0x100000;
4646
DefaultImageBase = 0x100000;
4747
}

‎lld/ELF/Config.h

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ struct Configuration {
159159
bool LTONewPassManager;
160160
bool MergeArmExidx;
161161
bool MipsN32Abi = false;
162+
bool Nmagic;
162163
bool NoinhibitExec;
163164
bool Nostdlib;
164165
bool OFormatBinary;
@@ -219,6 +220,7 @@ struct Configuration {
219220
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
220221
uint16_t EMachine = llvm::ELF::EM_NONE;
221222
llvm::Optional<uint64_t> ImageBase;
223+
uint64_t CommonPageSize;
222224
uint64_t MaxPageSize;
223225
uint64_t MipsGotSize;
224226
uint64_t ZStackSize;

‎lld/ELF/Driver.cpp

+43-6
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,8 @@ static bool isKnownZFlag(StringRef S) {
365365
S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" ||
366366
S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" ||
367367
S == "rodynamic" || S == "text" || S == "wxneeded" ||
368-
S.startswith("max-page-size=") || S.startswith("stack-size=");
368+
S.startswith("common-page-size") || S.startswith("max-page-size=") ||
369+
S.startswith("stack-size=");
369370
}
370371

371372
// Report an error for an unknown -z option.
@@ -829,6 +830,7 @@ static void readConfigs(opt::InputArgList &Args) {
829830
Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
830831
Config->MergeArmExidx =
831832
Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
833+
Config->Nmagic = Args.hasFlag(OPT_nmagic, OPT_no_nmagic, false);
832834
Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
833835
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
834836
Config->OFormatBinary = isOutputFormatBinary(Args);
@@ -957,11 +959,10 @@ static void readConfigs(opt::InputArgList &Args) {
957959
if (Args.hasArg(OPT_print_map))
958960
Config->MapFile = "-";
959961

960-
// --omagic is an option to create old-fashioned executables in which
961-
// .text segments are writable. Today, the option is still in use to
962-
// create special-purpose programs such as boot loaders. It doesn't
963-
// make sense to create PT_GNU_RELRO for such executables.
964-
if (Config->Omagic)
962+
// Page alignment can be disabled by the -n (--nmagic) and -N (--omagic).
963+
// As PT_GNU_RELRO relies on Paging, do not create it when we have disabled
964+
// it.
965+
if (Config->Nmagic || Config->Omagic)
965966
Config->ZRelro = false;
966967

967968
std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
@@ -1114,6 +1115,8 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
11141115
Config->AsNeeded = false;
11151116
break;
11161117
case OPT_Bstatic:
1118+
case OPT_omagic:
1119+
case OPT_nmagic:
11171120
Config->Static = true;
11181121
break;
11191122
case OPT_Bdynamic:
@@ -1199,6 +1202,29 @@ static uint64_t getMaxPageSize(opt::InputArgList &Args) {
11991202
Target->DefaultMaxPageSize);
12001203
if (!isPowerOf2_64(Val))
12011204
error("max-page-size: value isn't a power of 2");
1205+
if (Config->Nmagic || Config->Omagic) {
1206+
if (Val != Target->DefaultMaxPageSize)
1207+
warn("-z max-page-size set, but paging disabled by omagic or nmagic");
1208+
return 1;
1209+
}
1210+
return Val;
1211+
}
1212+
1213+
// Parse -z common-page-size=<value>. The default value is defined by
1214+
// each target.
1215+
static uint64_t getCommonPageSize(opt::InputArgList &Args) {
1216+
uint64_t Val = args::getZOptionValue(Args, OPT_z, "common-page-size",
1217+
Target->DefaultCommonPageSize);
1218+
if (!isPowerOf2_64(Val))
1219+
error("common-page-size: value isn't a power of 2");
1220+
if (Config->Nmagic || Config->Omagic) {
1221+
if (Val != Target->DefaultCommonPageSize)
1222+
warn("-z common-page-size set, but paging disabled by omagic or nmagic");
1223+
return 1;
1224+
}
1225+
// CommonPageSize can't be larger than MaxPageSize.
1226+
if (Val > Config->MaxPageSize)
1227+
Val = Config->MaxPageSize;
12021228
return Val;
12031229
}
12041230

@@ -1623,7 +1649,18 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
16231649
llvm::erase_if(InputSections, [](InputSectionBase *S) { return S->Debug; });
16241650

16251651
Config->EFlags = Target->calcEFlags();
1652+
// MaxPageSize (sometimes called abi page size) is the maximum page size that
1653+
// the output can be run on. For example if the OS can use 4k or 64k page
1654+
// sizes then MaxPageSize must be 64 for the output to be useable on both.
1655+
// All important alignment decisions must use this value.
16261656
Config->MaxPageSize = getMaxPageSize(Args);
1657+
// CommonPageSize is the most common page size that the output will be run on.
1658+
// For example if an OS can use 4k or 64k page sizes and 4k is more common
1659+
// than 64k then CommonPageSize is set to 4k. CommonPageSize can be used for
1660+
// optimizations such as DATA_SEGMENT_ALIGN in linker scripts. LLD's use of it
1661+
// is limited to writing trap instructions on the last executable segment.
1662+
Config->CommonPageSize = getCommonPageSize(Args);
1663+
16271664
Config->ImageBase = getImageBase(Args);
16281665

16291666
if (Config->EMachine == EM_ARM) {

‎lld/ELF/LinkerScript.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,10 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
993993
llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) {
994994
return Cmd.HasPhdrs || Cmd.HasFilehdr;
995995
});
996+
bool Paged = !Config->Omagic && !Config->Nmagic;
996997
uint64_t HeaderSize = getHeaderSize();
997-
if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) {
998+
if ((Paged || HasExplicitHeaders) &&
999+
HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) {
9981000
Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
9991001
Out::ElfHeader->Addr = Min;
10001002
Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;

‎lld/ELF/Options.td

+9-2
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ defm merge_exidx_entries: B<"merge-exidx-entries",
218218
"Enable merging .ARM.exidx entries (default)",
219219
"Disable merging .ARM.exidx entries">;
220220

221+
def nmagic: F<"nmagic">, MetaVarName<"<magic>">,
222+
HelpText<"Do not page align sections, link against static libraries.">;
223+
221224
def nostdlib: F<"nostdlib">,
222225
HelpText<"Only search directories specified on the command line">;
223226

@@ -230,8 +233,11 @@ def no_dynamic_linker: F<"no-dynamic-linker">,
230233
def noinhibit_exec: F<"noinhibit-exec">,
231234
HelpText<"Retain the executable output file whenever it is still usable">;
232235

236+
def no_nmagic: F<"no-nmagic">, MetaVarName<"<magic>">,
237+
HelpText<"Page align sections (default)">;
238+
233239
def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">,
234-
HelpText<"Do not set the text data sections to be writable">;
240+
HelpText<"Do not set the text data sections to be writable, page align sections (default)">;
235241

236242
def no_rosegment: F<"no-rosegment">,
237243
HelpText<"Do not put read-only non-executable sections in their own segment">;
@@ -246,7 +252,7 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
246252
HelpText<"Specify the binary format for the output object file">;
247253

248254
def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
249-
HelpText<"Set the text and data sections to be readable and writable">;
255+
HelpText<"Set the text and data sections to be readable and writable, do not page align sections, link against static libraries">;
250256

251257
defm orphan_handling:
252258
Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">;
@@ -414,6 +420,7 @@ def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
414420
def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
415421
def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
416422
def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
423+
def: Flag<["-"], "n">, Alias<nmagic>, HelpText<"Alias for --nmagic">;
417424
def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
418425
def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
419426
def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">;

‎lld/ELF/ScriptParser.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ Expr ScriptParser::getPageSize() {
10391039
std::string Location = getCurrentLocation();
10401040
return [=]() -> uint64_t {
10411041
if (Target)
1042-
return Target->PageSize;
1042+
return Config->CommonPageSize;
10431043
error(Location + ": unable to calculate page size");
10441044
return 4096; // Return a dummy value.
10451045
};

‎lld/ELF/Target.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class TargetInfo {
8181

8282
virtual ~TargetInfo();
8383

84-
unsigned PageSize = 4096;
84+
unsigned DefaultCommonPageSize = 4096;
8585
unsigned DefaultMaxPageSize = 4096;
8686

8787
uint64_t getImageBase() const;

‎lld/ELF/Writer.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,7 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
21322132
// segment is the last loadable segment, align the offset of the
21332133
// following section to avoid loading non-segments parts of the file.
21342134
if (LastRX && LastRX->LastSec == Sec)
2135-
Off = alignTo(Off, Target->PageSize);
2135+
Off = alignTo(Off, Config->CommonPageSize);
21362136
}
21372137

21382138
SectionHeaderOff = alignTo(Off, Config->Wordsize);
@@ -2184,7 +2184,7 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
21842184
// The glibc dynamic loader rounds the size down, so we need to round up
21852185
// to protect the last page. This is a no-op on FreeBSD which always
21862186
// rounds up.
2187-
P->p_memsz = alignTo(P->p_memsz, Target->PageSize);
2187+
P->p_memsz = alignTo(P->p_memsz, Config->CommonPageSize);
21882188
}
21892189

21902190
if (P->p_type == PT_TLS && P->p_memsz) {
@@ -2477,10 +2477,10 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
24772477
// Fill the last page.
24782478
for (PhdrEntry *P : Phdrs)
24792479
if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
2480-
fillTrap(Out::BufferStart +
2481-
alignDown(P->p_offset + P->p_filesz, Target->PageSize),
2480+
fillTrap(Out::BufferStart + alignDown(P->p_offset + P->p_filesz,
2481+
Config->CommonPageSize),
24822482
Out::BufferStart +
2483-
alignTo(P->p_offset + P->p_filesz, Target->PageSize));
2483+
alignTo(P->p_offset + P->p_filesz, Config->CommonPageSize));
24842484

24852485
// Round up the file size of the last segment to the page boundary iff it is
24862486
// an executable segment to ensure that other tools don't accidentally
@@ -2491,7 +2491,8 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
24912491
Last = P;
24922492

24932493
if (Last && (Last->p_flags & PF_X))
2494-
Last->p_memsz = Last->p_filesz = alignTo(Last->p_filesz, Target->PageSize);
2494+
Last->p_memsz = Last->p_filesz =
2495+
alignTo(Last->p_filesz, Config->CommonPageSize);
24952496
}
24962497

24972498
// Write section contents to a mmap'ed file.

‎lld/docs/ld.lld.1

+7-1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ Set target emulation.
254254
.It Fl -Map Ns = Ns Ar file , Fl M Ar file
255255
Print a link map to
256256
.Ar file .
257+
.It Fl -nmagic , Fl n
258+
Do not page align sections, link against static libraries.
257259
.It Fl -no-allow-shlib-undefined
258260
Do not allow unresolved references in shared libraries.
259261
This option is enabled by default when linking an executable.
@@ -277,6 +279,10 @@ Disable garbage collection of unused sections.
277279
Disable STB_GNU_UNIQUE symbol binding.
278280
.It Fl -no-merge-exidx-entries
279281
Disable merging .ARM.exidx entries.
282+
.It F1 -no-nmagic
283+
Page align sections.
284+
.It F1 -no-omagic
285+
Do not set the text data sections to be writable, page align sections.
280286
.It Fl -no-rosegment
281287
Do not put read-only non-executable sections in their own segment.
282288
.It Fl -no-threads
@@ -325,7 +331,7 @@ is
325331
.Cm binary ,
326332
which produces output with no ELF header.
327333
.It Fl -omagic , Fl N
328-
Set the text and data sections to be readable and writable.
334+
Set the text and data sections to be readable and writable, do not page align sections, link against static libraries.
329335
.It Fl -opt-remarks-filename Ar file
330336
Write optimization remarks in YAML format to
331337
.Ar file .

0 commit comments

Comments
 (0)
Please sign in to comment.